using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine.AI;
using Yoozoo.Mars.Got;

// Build and update a localized navmesh from the sources marked by NavMeshSourceTag
[DefaultExecutionOrder(-102)]
[RequireComponent(typeof(NavMeshSourceTag))]
public class LocalNavMeshBuilder : MonoBehaviour
{
#if UNITY_EDITOR && !UNITY_WEBGL
    // The center of the build
    public Transform m_Tracked;

    // The size of the build bounds
    public Vector3 m_Size = new Vector3(200f, 20.0f, 200);

    NavMeshData m_NavMesh;
    AsyncOperation m_Operation;
    NavMeshDataInstance m_Instance;
    List<NavMeshBuildSource> m_Sources = new List<NavMeshBuildSource>();
    public string path = "Assets/ResourcesAssets/OuterCity/Map/Normal/NavMeshSource.obj";
    private string serverPath = "Assets/ResourcesAssets/OuterCity/Map/Normal/NavMeshSource_server.obj";
    public string prefabPath = "Assets/ResourcesAssets/OuterCity/Map/Normal/NavMeshSourcePrefab.prefab";
    private bool isInit = false;
    private MeshFilter meshFilterCombine;


    void OnEnable()
    {
        // Construct and add navmesh
        // m_NavMesh = new NavMeshData();
        // m_Instance = NavMesh.AddNavMeshData(m_NavMesh);
        // if (m_Tracked == null)
        //     m_Tracked = transform;
        //Timers.inst.CallLater((o) =>
        //{
            //UpdateNavMesh(false);
            //SaveData();
        //});
    }

    void Update()
    {
        return;
        if (!isInit)
        {
            SaveData();
            //LoadData();

            isInit = true;
        }

    }

    private void SaveData()
    {
        CombineMeshAndSave();
    }

    private void LoadData()
    {
        var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
        var go = GameObject.Instantiate(prefab);
        meshFilterCombine = prefab.GetOrAddCompoment<MeshFilter>();
        //meshFilterCombine.mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
        UpdateMeshByCombine();

    }

    private void CombineMeshAndSave()
    {
        NavMeshSourceTag.Collect(ref m_Sources);
        var defaultBuildSettings = NavMesh.GetSettingsByID(0);
        defaultBuildSettings.agentRadius = 0.6f;
        defaultBuildSettings.agentHeight = 0;
        defaultBuildSettings.agentSlope = 45;
        defaultBuildSettings.minRegionArea = 8;
        defaultBuildSettings.voxelSize = 0.3f;

        var bounds = QuantizedBounds();

        NavMeshBuilder.UpdateNavMeshData(m_NavMesh, defaultBuildSettings, m_Sources, bounds);
        NavMeshTriangulation triangulatedNavMesh = NavMesh.CalculateTriangulation();
        var prefab = new GameObject("prefab");
        meshFilterCombine = prefab.GetOrAddCompoment<MeshFilter>();

        Mesh mesh = new Mesh();
        mesh.name = "_NavMesh";
        mesh.vertices = triangulatedNavMesh.vertices;
        mesh.triangles = triangulatedNavMesh.indices;
        meshFilterCombine.mesh = mesh;
        using (StreamWriter streamWriter = new StreamWriter(path))
        {
            streamWriter.Write(MeshToString(meshFilterCombine, new Vector3(-1f, 1f, 1f)));
            streamWriter.Close();
        }
        AssetDatabase.Refresh();
        meshFilterCombine.mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
        PrefabUtility.SaveAsPrefabAsset(prefab,prefabPath);
        AssetDatabase.Refresh();

        //UpdateMeshByCombine();
    }

    private string MeshToString(MeshFilter mf, Vector3 scale)
    {
        Mesh          mesh            = mf.sharedMesh;
        StringBuilder stringBuilder   = new StringBuilder().Append("mtllib design.mtl")
            .Append("\n")
            .Append("g ")
            .Append(mf.name)
            .Append("\n");
        Vector3[] vertices = mesh.vertices;
        for (int i = 0; i < vertices.Length; i++)
        {
            Vector3 vector = vertices[i];
            stringBuilder.Append(string.Format("v {0} {1} {2}\n", vector.x * scale.x, vector.y * scale.y, vector.z * scale.z));
        }
        stringBuilder.Append("\n");
        Dictionary<int, int> dictionary = new Dictionary<int, int>();
        if (mesh.subMeshCount > 1)
        {
            int[] triangles = mesh.GetTriangles(1);
            for (int j = 0; j < triangles.Length; j += 3)
            {
                if (!dictionary.ContainsKey(triangles[j]))
                {
                    dictionary.Add(triangles[j], 1);
                }
                if (!dictionary.ContainsKey(triangles[j + 1]))
                {
                    dictionary.Add(triangles[j + 1], 1);
                }
                if (!dictionary.ContainsKey(triangles[j + 2]))
                {
                    dictionary.Add(triangles[j + 2], 1);
                }
            }
        }
        for (int num = 0; num != mesh.uv.Length; num++)
        {
            Vector2 vector2 = mesh.uv[num];
            if (dictionary.ContainsKey(num))
            {
                stringBuilder.Append(string.Format("vt {0} {1}\n", mesh.uv[num].x, mesh.uv[num].y));
            }
            else
            {
                stringBuilder.Append(string.Format("vt {0} {1}\n", vector2.x, vector2.y));
            }
        }
        for (int k = 0; k < mesh.subMeshCount; k++)
        {
            stringBuilder.Append("\n");
            if (k == 0)
            {
                stringBuilder.Append("usemtl ").Append("Material_design").Append("\n");
            }
            if (k == 1)
            {
                stringBuilder.Append("usemtl ").Append("Material_logo").Append("\n");
            }
            int[] triangles2 = mesh.GetTriangles(k);
            for (int l = 0; l < triangles2.Length; l += 3)
            {
                stringBuilder.Append(string.Format("f {0}/{0} {1}/{1} {2}/{2}\n", triangles2[l] + 1, triangles2[l + 2] + 1, triangles2[l + 1] + 1));
            }
        }
        return stringBuilder.ToString();
    }


    void OnDisable()
    {
        // Unload navmesh and clear handle
        m_Instance.Remove();
    }

    void UpdateNavMesh()
    {
        NavMeshSourceTag.Collect(ref m_Sources);
        var defaultBuildSettings = NavMesh.GetSettingsByID(0);
        defaultBuildSettings.agentHeight = 0;
        var bounds = QuantizedBounds();

        NavMeshBuilder.UpdateNavMeshData(m_NavMesh, defaultBuildSettings, m_Sources, bounds);
    }

    private void UpdateMeshByCombine()
    {
        NavMeshSourceTag.m_Meshes.Clear();
        NavMeshSourceTag.m_Meshes.Add(meshFilterCombine);
        NavMeshSourceTag.Collect(ref m_Sources);
        var defaultBuildSettings = NavMesh.GetSettingsByID(0);
        defaultBuildSettings.agentHeight = 0;
        var bounds = QuantizedBounds();
        NavMeshBuilder.UpdateNavMeshData(m_NavMesh, defaultBuildSettings, m_Sources, bounds);
    }

    static Vector3 Quantize(Vector3 v, Vector3 quant)
    {
        float x = quant.x * Mathf.Floor(v.x / quant.x);
        float y = quant.y * Mathf.Floor(v.y / quant.y);
        float z = quant.z * Mathf.Floor(v.z / quant.z);
        return new Vector3(x, y, z);
    }

    Bounds QuantizedBounds()
    {
        // Quantize the bounds to update only when theres a 10% change in size
        var center = m_Tracked ? m_Tracked.position : transform.position;
        return new Bounds(Quantize(center, 0.1f * m_Size), m_Size);
    }

    void OnDrawGizmosSelected()
    {
        if (m_NavMesh)
        {
            Gizmos.color = Color.green;
            Gizmos.DrawWireCube(m_NavMesh.sourceBounds.center, m_NavMesh.sourceBounds.size);
        }

        Gizmos.color = Color.yellow;
        var bounds = QuantizedBounds();
        Gizmos.DrawWireCube(bounds.center, bounds.size);

        Gizmos.color = Color.green;
        var center = m_Tracked ? m_Tracked.position : transform.position;
        Gizmos.DrawWireCube(center, m_Size);
    }

    [ContextMenu("SaveLocal")]
    private void SaveLocal()
    {
        NavMeshTriangulation triangulatedNavMesh = NavMesh.CalculateTriangulation();
        var prefab = new GameObject("prefab");
        meshFilterCombine = prefab.GetOrAddCompoment<MeshFilter>();

        Mesh mesh = new Mesh();
        mesh.name = "_NavMesh";
        mesh.vertices = triangulatedNavMesh.vertices;
        mesh.triangles = triangulatedNavMesh.indices;
        meshFilterCombine.mesh = mesh;
        using (StreamWriter streamWriter = new StreamWriter(path))
        {
            streamWriter.Write(MeshToString(meshFilterCombine, new Vector3(-1f, 1f, 1f)));
            streamWriter.Close();
        }
        AssetDatabase.Refresh();
        meshFilterCombine.mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
        PrefabUtility.SaveAsPrefabAsset(prefab,prefabPath);
        AssetDatabase.Refresh();
        Selection.activeGameObject = prefab;
        EditorUtility.FocusProjectWindow();
        Debug.Log($"SaveLocal <color=yellow> Success!</color> {path}");

    }


    // // 导出给服务器使用
    // [ContextMenu("ExportToSever")]
    // private void ExportToSever()
    // {
    //     NavMeshTriangulation triangulatedNavMesh = NavMesh.CalculateTriangulation();
    //     Mesh mesh = new Mesh();
    //     mesh.name = "_NavMesh";
    //     mesh.vertices = triangulatedNavMesh.vertices;
    //     mesh.triangles = triangulatedNavMesh.indices;
    //     meshFilterCombine.mesh = mesh;
    //     using (StreamWriter streamWriter = new StreamWriter(serverPath))
    //     {
    //         streamWriter.Write(MeshToString(meshFilterCombine, new Vector3(1f, 1f, 1f)));
    //         streamWriter.Close();
    //     }
    //
    //     AssetDatabase.Refresh();
    //     Debug.Log($"ExportToSever <color=yellow> Success!</color> {path}");
    // }



#endif
}
